	package com.linchong.concurrency.lock;

	import com.linchong.concurrency.annoations.ThreadSafe;
	import lombok.extern.slf4j.Slf4j;

	import java.util.concurrent.CountDownLatch;
	import java.util.concurrent.ExecutorService;
	import java.util.concurrent.Executors;
	import java.util.concurrent.Semaphore;
	import java.util.concurrent.locks.Lock;
	import java.util.concurrent.locks.ReentrantLock;

	/**
	 * @author linchong
	 * @version 1.0
	 * @Date: 2020-12-08 12:40
	 * @Description: ConcurrencyTest$
	 */
	@Slf4j
	@ThreadSafe
	public class LockExample2 {

		/**
		 * 请求总数
		 */
		private static int clientTotal = 5000;

		/**
		 * 同时执行的线程数
		 */
		private static int threadTotal = 200;

		private static Lock lock = new ReentrantLock();
		private static int count = 0;

		public static void main(String[] args) throws Exception {
			ExecutorService executorService = Executors.newCachedThreadPool();
			//允许同时执行的并发请求数，
			// 阻塞进程，控制同一时间的请求的并发量
			// 适合控制同时并发的线程数
			final Semaphore semaphore = new Semaphore(threadTotal);

			//所有请求执行完，统计结果
			// 闭锁，调用countdownLatch.await()方法阻塞，其他线程调用countdownLatch.countDown()方法，减一，
			// 当计数器值为0时，程序继续执行
			// 可以阻塞线程，并保证线程在满足某种特定的条件下，继续执行
			// 适合保证线程执行完之后继续其他的处理
			final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
			// 模拟并发测试，并在所有线程执行完之后输出结果，两者结合
			for (int i = 0; i < clientTotal; i++) {
				executorService.execute(() -> {
					try {
						//当前线程是否允许被执行，否则，阻塞
						semaphore.acquire();
						add();
						semaphore.release();
					} catch (InterruptedException e) {
						log.error("exception", e);
					}
					countDownLatch.countDown();
				});
			}
			//可以保证之前的countdown必须减为0
			// 即线程池中所有线程都执行完成，否则，一直阻塞
			countDownLatch.await();
			log.info("count:{}", count);
			executorService.shutdown();
		}

		private static void add() {
			lock.lock();
			try {
				count++;
			} finally {
				lock.unlock();
			}
		}
	}
